﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr.Runtime.Tree;
using Magic.Framework.OQL.Factory;
using Magic.Framework.OQL.Expressions;
using System.Diagnostics;
using Ddbs.QE.Parser.Front.Serialization;

namespace   Magic.Framework.OQL
{
    

    public partial class SQLParser : Antlr.Runtime.Parser
    {
        partial void CreateTreeAdaptor(ref ITreeAdaptor adaptor)
        {
            adaptor = new TreeFactory();
        }
    }
    
   public class SQLContext
   {
       private static Dictionary<int, ConditionType> typeMap;

       public static Dictionary<int, ConditionType> TypeMap
       {
           get { return SQLContext.typeMap; }
           set { SQLContext.typeMap = value; }
       }
       
       static SQLContext()
       {
           typeMap = new Dictionary<int, ConditionType>();
           typeMap[SQLParser.Eq] = ConditionType.EQ;
           typeMap[SQLParser.NOT] = ConditionType.NOT;
           typeMap[SQLParser.AND] = ConditionType.AND;
           typeMap[SQLParser.OR] = ConditionType.OR;
           typeMap[SQLParser.Le1] = ConditionType.LE;
           typeMap[SQLParser.Le2] = ConditionType.LE;
           typeMap[SQLParser.Lt] = ConditionType.LT;
           typeMap[SQLParser.Ge1] = ConditionType.GE;
           typeMap[SQLParser.Ge2] = ConditionType.GE;
           typeMap[SQLParser.Gt] = ConditionType.GT;
            
       }

       private IList<Ddbs.QE.Parser.Front.Serialization.Column> columns;
       private IList<Ddbs.QE.Parser.Front.Serialization.Table> tables;
       private Ddbs.QE.Parser.Front.Serialization.Condition cond;


       public IList<Ddbs.QE.Parser.Front.Serialization.Column> Columns
       {
           get { return columns; }
           set { columns = value; }
       }


       public IList<Ddbs.QE.Parser.Front.Serialization.Table> Tables
       {
           get { return tables; }
           set { tables = value; }
       }


       public Ddbs.QE.Parser.Front.Serialization.Condition Cond
       {
           get { return cond; }
           set { cond = value; }
       }

   }

    public class SQLParserHeler
    {
        private static List<Ddbs.QE.Parser.Front.Serialization.Column> extractColumns(IList<Expressions.Column> cols)
        {
            List<Ddbs.QE.Parser.Front.Serialization.Column> columns = new List<Ddbs.QE.Parser.Front.Serialization.Column>();
            foreach(Expressions.Column col in cols)
            {
                Ddbs.QE.Parser.Front.Serialization.Column column = new Ddbs.QE.Parser.Front.Serialization.Column();
                column.HasTableName = col.HasTableName;
                column.IsAllColumn = col.IsAllColumn;
                column.TableName = col.TableName;
                column.ColumnName = col.ColumnName;
                columns.Add(column);
            }
            
            return columns;
        }

        private static IList<Ddbs.QE.Parser.Front.Serialization.Table> extractTables(IList<Expressions.Table> tables)
        {
            IList<Ddbs.QE.Parser.Front.Serialization.Table> tbls = new List<Ddbs.QE.Parser.Front.Serialization.Table>();
            foreach (Expressions.Table table in tables)
            {
                Ddbs.QE.Parser.Front.Serialization.Table tbl = new Ddbs.QE.Parser.Front.Serialization.Table();
                tbl.Name = table.TableName;
                tbls.Add(tbl);
            }
            return tbls;
        }

        private static Ddbs.QE.Parser.Front.Serialization.Condition extractCondition(Expression cond)
        {
            if (cond == null) return null;
            if (cond.ChildCount == 0)
            {
                string s;
                switch (cond.Type)
                {
                    case SQLParser.NonQuotedIdentifier:
                        s = cond.Text;
                        ColumnVal val = new ColumnVal();
                        val.ColumnRef = new Ddbs.QE.Parser.Front.Serialization.Column();
                        val.Type = ConditionType.COLUMN;
                        int dot = s.IndexOf('.') ;
                        if (dot != -1)
                        {
                            
                            
                            val.ColumnRef.HasTableName = true;
                            val.ColumnRef.TableName = s.Substring(0, dot);
                            val.ColumnRef.ColumnName = s.Substring(dot + 1);
                        }
                        else {
                            val.ColumnRef.HasTableName = false;
                            val.ColumnRef.ColumnName = s;
                        }
                        val.ColumnRef.IsAllColumn = (val.ColumnRef.TableName == "*");
                        return val;

                    case SQLParser.TextNode:
                         s= cond.Text;
                         if (s[0] == '\'' || s[0] == '\"')
                         {
                             StrVal strval = new StrVal();
                             strval.Type = ConditionType.STRVAL;
                             strval.Val = s.Substring(1, s.Length - 2);
                             return strval;
                         }
                         else {
                             IntVal intval = new IntVal();
                             intval.Type = ConditionType.INTVAL;
                             intval.Val = int.Parse(s);
                             return intval;
                         }
                        
                       
                }
            }
            Ddbs.QE.Parser.Front.Serialization.Condition tmp = new Ddbs.QE.Parser.Front.Serialization.Condition();
            if (cond.Type != SQLParser.Predicate 
                && cond.Type != SQLParser.Group)
            {
                tmp.Type = SQLContext.TypeMap[cond.Type];
            }
            tmp.Children = new List<Ddbs.QE.Parser.Front.Serialization.Condition>();
            switch (cond.Type)
            {
                case SQLParser.AND:
                    
                    tmp.Children.Add(extractCondition(cond.GetChild(0)));
                    tmp.Children.Add(extractCondition(cond.GetChild(1)));
                    break;
                case SQLParser.OR:
                    
                    tmp.Children.Add(extractCondition(cond.GetChild(0)));
                    tmp.Children.Add(extractCondition(cond.GetChild(1)));
                    break;
                case SQLParser.NOT:
                    
                    tmp.Children.Add(extractCondition(cond.GetChild(0)));
                    break;
                case SQLParser.Group:
                    tmp = extractCondition(cond.GetChild(0));
                    break;
                case SQLParser.Predicate:
                    tmp.Type = SQLContext.TypeMap[cond.GetChild(1).Type];
                    tmp.Children.Add(extractCondition(cond.GetChild(0)));
                    tmp.Children.Add(extractCondition(cond.GetChild(2)));
                    break;

            }
            return tmp;
        }
        public static List<SQLContext> extractSQLContexts(SQLParser.start_return root)
        {
            List<SQLContext> contexts = new List<SQLContext>();
            if (root != null && root.Tree != null)
            {
                int num = root.Tree.ChildCount;
                for (int i = 0; i < num; ++i)
                {
                    Expression child = root.Tree.GetChild(i);
                    if (SelectStatement.IsSelectStatement(child))
                    {
                        SelectStatement selectStatement = (SelectStatement)child;
                        if (selectStatement.HasSelectClause == true)
                        {
                            SelectClause selectClause = (SelectClause)selectStatement.GetChild(0);
                            SQLContext context = new SQLContext();
                            context.Columns = extractColumns(selectClause.Columns);
                            FromClause fromClause = (FromClause)selectStatement.GetFromClause();
                            context.Tables = extractTables(fromClause.Tables);
                            if (selectStatement.HasWhereClause == true)
                            {
                                context.Cond = extractCondition(selectStatement.GetWhereCondition());
                            }
                            contexts.Add(context);

                        }
                    }
                }
                
            }
            return contexts;
        }

        private static void visitCondition(Ddbs.QE.Parser.Front.Serialization.Condition c, int n)
        {
            if (c == null)
                return;
            int i = 0;
            Console.Write(n);
            for (; i < n; ++i)
            {
                Console.Write("\t");
            }

            if (c.Type < Ddbs.QE.Parser.Front.Serialization.ConditionType.COLUMN)
            {
                Console.WriteLine(c.Type.ToString());
                for (i = 0; i < c.Children.Count; ++i)
                {
                    visitCondition(c.Children.ElementAt(i), n + 1);
                }
            }
            else
            {
                Console.WriteLine(c.ToString());
            }
        }
        public static void printContext(SQLContext sql)
        {
            Console.WriteLine("begin column names");
            int i = 0;
            foreach (Ddbs.QE.Parser.Front.Serialization.Column c in sql.Columns)
            {
                ++i;
                Console.WriteLine("column " + i);
                if (c.HasTableName)
                    Console.WriteLine("table name: " + c.TableName);


                if (!c.IsAllColumn)
                {

                    //if (c.HasColumnName)
                    Console.WriteLine("column name: " + c.ColumnName);

                }
                else
                {

                    Console.WriteLine("column name: *");

                }

            }
            Console.WriteLine("end column names");
            Console.WriteLine("begin table names");
            i = 0;
            foreach (Ddbs.QE.Parser.Front.Serialization.Table t in sql.Tables)
            {
                ++i;
                Console.WriteLine("table " + i);
                Console.WriteLine("Table name: " + t.Name);
            }
            Console.WriteLine("end table names");
            Console.WriteLine("begin condition");
            visitCondition(sql.Cond as Ddbs.QE.Parser.Front.Serialization.Condition, 0);
            Console.WriteLine("end condition");
        }

        
       
    }
}
